Skip to content

[19.0][IMP] fs_attachments: fix parsing of stored filenames when storing locally - #638

Open
CRogos wants to merge 1 commit into
OCA:19.0from
c4a8-odoo:19.0-imp-fs_attachments
Open

[19.0][IMP] fs_attachments: fix parsing of stored filenames when storing locally#638
CRogos wants to merge 1 commit into
OCA:19.0from
c4a8-odoo:19.0-imp-fs_attachments

Conversation

@CRogos

@CRogos CRogos commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Solves this error when new attachments should be stored locally:

RPC_ERROR

Odoo Server Error

Occured on c4a8-18-0-dev-34353123.dev.odoo.com on model hr.expense on 2026-07-03 09:32:36 GMT

Traceback (most recent call last):
  File "/home/odoo/src/odoo/odoo/http.py", line 2329, in _serve_db
    return service_model.retrying(serve_func, env=self.env)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/src/odoo/odoo/service/model.py", line 190, in retrying
    env.cr.flush()  # submit the changes to the database
    ^^^^^^^^^^^^^^
  File "/home/odoo/src/odoo/odoo/sql_db.py", line 182, in flush
    self.transaction.flush()
  File "/home/odoo/src/odoo/odoo/orm/environments.py", line 592, in flush
    self.default_env.flush_all()
  File "/home/odoo/src/odoo/odoo/orm/environments.py", line 383, in flush_all
    self._recompute_all()
  File "/home/odoo/src/odoo/odoo/orm/environments.py", line 376, in _recompute_all
    self[field.model_name]._recompute_field(field)
  File "/home/odoo/src/odoo/odoo/orm/models.py", line 6960, in _recompute_field
    field.recompute(records)
  File "/home/odoo/src/odoo/odoo/orm/fields.py", line 1891, in recompute
    apply_except_missing(self.compute_value, recs)
  File "/home/odoo/src/odoo/odoo/orm/fields.py", line 1861, in apply_except_missing
    func(records)
  File "/home/odoo/src/odoo/odoo/orm/fields.py", line 1915, in compute_value
    records._compute_field_value(self)
  File "/home/odoo/src/odoo/odoo/orm/models.py", line 4954, in _compute_field_value
    determine(field.compute, self)
  File "/home/odoo/src/odoo/odoo/orm/fields.py", line 81, in determine
    return needle(*args)
           ^^^^^^^^^^^^^
  File "/home/odoo/src/user/modules/oca/storage/fs_attachment/models/ir_attachment.py", line 114, in _compute_fs_url
    new_url = self.env["fs.storage"]._get_url_for_attachment(rec)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/src/user/modules/oca/storage/fs_attachment/models/fs_storage.py", line 266, in _get_url_for_attachment
    _fs, storage_code, file_path = attachment._get_fs_parts()
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/src/user/modules/oca/storage/fs_attachment/models/ir_attachment.py", line 597, in _get_fs_parts
    return self._fs_parse_store_fname(self.store_fname)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/src/user/modules/oca/storage/fs_attachment/models/ir_attachment.py", line 527, in _fs_parse_store_fname
    fs = self._get_fs_storage_for_code(storage_code)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/src/user/modules/oca/storage/fs_attachment/models/ir_attachment.py", line 509, in _get_fs_storage_for_code
    raise SystemError(f"No Filesystem storage for code {code}")
SystemError: No Filesystem storage for code 91/91e790cb58ba34fef3a9c34c15bdef1818b9c82b

The above server error caused the following client error:
RPC_ERROR: Odoo Server Error
    RPCError@https://c4a8-18-0-dev-34353123.dev.odoo.com/web/assets/094bae2/web.assets_web.min.js:3180:78
    makeErrorFromResponse@https://c4a8-18-0-dev-34353123.dev.odoo.com/web/assets/094bae2/web.assets_web.min.js:3184:165
    rpc._rpc/promise</<@https://c4a8-18-0-dev-34353123.dev.odoo.com/web/assets/094bae2/web.assets_web.min.js:3191:34
    

@OCA-git-bot

Copy link
Copy Markdown
Contributor

Hi @lmignon,
some modules you are maintaining are being modified, check this out!

@CRogos
CRogos force-pushed the 19.0-imp-fs_attachments branch from e71df9a to 9083b3f Compare July 3, 2026 10:02
@lmignon

lmignon commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

@CRogos Can you explain your use case? I can't imagine the context in which you're encountering this problem. How can I reproduce your issue?

@CRogos

CRogos commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

The error occurred when trying to post an expense in our staging system.

Because we don't want that any attachment of the production system is deleted by accident from the staging server, we replace the read/write credentials with with readonly credentials by an neutralize.sql script. We also deactivate that new attachments are uploaded to the cloud storage from the staging system, by removing all models from the fs.storage setting. Instead they are stored the usual odoo.sh way on the server. All attachments which were copied from the production system are still accessible by the readonly connection.

UPDATE fs_storage
      SET server_env_defaults = REPLACE(
          (
              SELECT value
                FROM ir_config_parameter
                WHERE key = 'c4a8_setting.fs_storage_env_azure_readonly'
          ),
          '"x_directory_path_env_default": ""',
          CONCAT('"x_directory_path_env_default": "', code, '"')
      )
      WHERE code like 'azure-%';

So the error occurs when the module is installed, but the new attachment is not stored in the cloud instead on the native story.

@lmignon

lmignon commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

@CRogos IMO, the issue you're experiencing comes from the way the library is being used and how your staging process is managed. We have never encountered this problem because our approach is different.

With your current approach, you can end up with records whose data is inconsistent with the storage configuration. If I understand your explanation correctly, you're mixing records from different storages that are associated with the same storage configuration.

A safer approach for a staging environment is to add a dedicated storage backend and configure it as the default for attachments (https://github.com/OCA/storage/tree/18.0/fs_attachment#tips--tricks). At the same time, you can configure the production storage to use a read-only user. This avoids inconsistencies while still allowing you to work safely with production data.

@lmignon lmignon added question Further information is requested invalid This doesn't seem right labels Jul 27, 2026
@CRogos

CRogos commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

With your current approach, you can end up with records whose data is inconsistent with the storage configuration. If I understand your explanation correctly, you're mixing records from different storages that are associated with the same storage configuration.

No, I actually only disable all configurations from write access by removing all models from the configuration and changing the credentials with read only access.
As a result, no matching configuration is found for new files and therefore are written to the default, like you suggested but without an explicit configuration. So the only difference is that I do not create an explicit local file configuration, instead I use the default odoo behavior.

Could it be, that there is no "://" in the file path by odoo default, and therefore _fs_parse_store_fname is called without "://" in the url? I agree that when creating an explicit file default configuration for the staging system, the url would look something like this "local-file://..." and therefore the error should not occur, but I think the module should not crash, if the odoo native format is used, instead it should behave like odoo native.

@lmignon

lmignon commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

In your stack_trace, the error occurs into the method compute of the fs_url. Nevertheless this compute only occurs if your attachment has a fs_filename and the fs_filename should only be filled if the attachment is stored into a configured fs_storage 🤔 ....

@lmignon

lmignon commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

The method _fs_parse_store_fname should only be called if the attachment is linked to a fs_storage.... and in such a case the fname should contain "://" 🤔 🤔 🤔

@CRogos

CRogos commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

This is my configuration. The only difference between prod/staging is client_id/_secret and on staging all model_ids are removed.

image image

@lmignon

lmignon commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

The place where the error occurs is into a record that should be linked to fs_storage
image
image
Can you check why you've a fs_filename with a fname that doesn't contain '://'?

@CRogos

CRogos commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

I think this ir_attachment is not connected to any fs_storage.

@lmignon

lmignon commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

I think this ir_attachment is not connected to any fs_storage.

In such a case, fs_filename should be False and the method not called.

@CRogos

CRogos commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

I agree... I assume _compute_fs_url is called for new record.
Is fs_storage_id already set? Than we should change this method, so rec.fs_url is set to False if not rec.fs_storage_id

@api.depends("fs_filename")
def _compute_fs_url(self) -> None:
for rec in self:
new_url = None
actual_url = rec.fs_url or None
if rec.fs_filename:
new_url = self.env["fs.storage"]._get_url_for_attachment(rec)
# ensure we compare value of same type and not None with False
new_url = new_url or None
if new_url != actual_url:
rec.fs_url = new_url

@lmignon

lmignon commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

@CRogos The guard is if rec.fs_filename ... This field should never be set if no fs_folder_id.

@CRogos

CRogos commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Not sure if this is the case here, but we should also consider this scenario:
The attachment exists on fs_storage, than the configuration is changed and new content should be stored locally (no explicit configuration).
The storage configuration (for read) is still on the attachment record, when the new content is set and _compute_fs_url is called.

@lmignon

lmignon commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Not sure if this is the case here, but we should also consider this scenario: The attachment exists on fs_storage, than the configuration is changed and new content should be stored locally (no explicit configuration). The storage configuration (for read) is still on the attachment record, when the new content is set and _compute_fs_url is called.

In such a case, the attachment is linked to a storage. If the configuration is stored on the record, then the record is linked to a storage. But once again, we already have a guard with if rec.fs_filename. I'm sorry but without a proper understanding of the actual issue, the proposed fix may not be valid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

invalid This doesn't seem right mod:fs_attachment Module fs_attachment question Further information is requested series:19.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants